﻿#region License
/* ---------------------------------------------------------------- *
 *
 * This file is part of the API Concepts Framework
 * http://apiconceptsframework.codeplex.com
 *
 * Copyright (C) 2014 eva Kühn, Thomas Scheller, Vienna University of Technology
 * http://www.complang.tuwien.ac.at/eva
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/
 *
 * ---------------------------------------------------------------- */
#endregion

using System;
using ApiConceptsFramework.Contract;

namespace ApiConceptsFramework
{
	public class LearningEffect
	{
		public static readonly LearningEffect Search = new LearningEffect(1, 1.25f, 1);
		public static readonly LearningEffect Usage = new LearningEffect(0.4f, 2);

		private readonly float _maxLearningReduction;
		private readonly float _learningSteps;
		private readonly float _reductionForMultipleUsagesInSameContext;

		public LearningEffect(float maxLearningReduction, float learningSteps)
			: this(maxLearningReduction, learningSteps, Math.Min(1, maxLearningReduction*1.5f)) //reduction in same context is by default x1,5 higher than max learning reduction
		{
		}

		public LearningEffect(float maxLearningReduction, float learningSteps, float reductionForMultipleUsagesInSameContext)
		{
			_maxLearningReduction = maxLearningReduction;
			_learningSteps = learningSteps;
			_reductionForMultipleUsagesInSameContext = reductionForMultipleUsagesInSameContext;
		}

		public float MaxLearningReduction
		{
			get { return _maxLearningReduction; }
		}

		public float LearningSteps
		{
			get { return _learningSteps; }
		}

		public float ReductionForMultipleUsagesInSameContext
		{
			get { return _reductionForMultipleUsagesInSameContext; }
		}

		public float CalculateComplexity(float baseComplexity, int usage, int previousUsages)
		{
			if (usage < 1)
				throw new ArgumentException("usage must be > 0", "usage");
			if (usage > 1)
				return baseComplexity * (1 - _reductionForMultipleUsagesInSameContext); //max reduction for every consecutive usage within one code piece, independent of previous usages
			usage += previousUsages; //if first usage: calculage learning effect depending on previous usages
			if (usage == 1)
				return baseComplexity;
			if (usage > (int)Math.Ceiling(LearningSteps)) //if steps is no whole number, it needs to be rounded up
				return baseComplexity*(1 - MaxLearningReduction);
			return baseComplexity*(1 - (MaxLearningReduction*(usage - 1)/LearningSteps));
		}

		public float CalculateComplexityForMultipleUsages(float baseComplexity, int numberOfUsages, int previousUsages)
		{
			float complexity = 0;
			//string str = "";
			for (int i = (1); i <= (numberOfUsages); i++)
			{
				var compl = CalculateComplexity(baseComplexity, i, previousUsages);
				complexity += compl;
				//str += "+" + compl;
			}
			//Console.WriteLine(str);
			return complexity;
		}
	}
}